package controllerService

import (
	"errors"
	"gitee.com/fierce_wolf/go-fox-edge-common/commConfig"
	"gitee.com/fierce_wolf/go-fox-edge-common/commEntityManager"
	"gitee.com/fierce_wolf/go-fox-edge-common/commRedisRpc"
	"gitee.com/fierce_wolf/go-fox-edge-common/commRedisService"
	"gitee.com/fierce_wolf/go-fox-edge-common/commRedisStatus"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Map"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Method"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Number"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/TimeInterval"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Uuid"
	"gitee.com/fierce_wolf/go-fox-edge-common/edgeEntity"
	"time"
)

type CollectorExchangeService struct {
	timeIntervalMap TimeInterval.TimeInterval
}

// Scheduler 创建一个线程
func (e *CollectorExchangeService) Scheduler() {
	go e.scheduler()
}

// 线程函数
func (e *CollectorExchangeService) scheduler() {
	for true {
		time.Sleep(1 * time.Second)
		if !commEntityManager.EntityManager.Initialized {
			time.Sleep(1 * time.Second)
			continue
		}

		// 检测：持久化服务接收队列是否堵塞了
		if block, err := commRedisRpc.Persist.Client.ValueRequest.IsBlock(); err != nil || block == true {
			continue
		}

		// 取出数据
		entityMap, err := commRedisService.GetEntityMap(edgeEntity.Type.OperateMonitorTaskEntity.Type())
		if err != nil {
			continue
		}

		for _, entity := range entityMap {
			taskEntity := entity.(*edgeEntity.OperateMonitorTaskEntity)

			CollectorExchange.ExecuteTask(taskEntity)
		}
	}
}

// ExecuteTask 线程函数
func (e *CollectorExchangeService) ExecuteTask(taskEntity *edgeEntity.OperateMonitorTaskEntity) {
	currentTime := time.Now().UnixMilli()
	timeInv, err := e.getTimeInterval(taskEntity)
	if err != nil {
		return
	}

	// 检查：是否到了执行周期
	if !e.timeIntervalMap.TestLastTime(taskEntity.TemplateName, time.Now().UnixMilli(), timeInv) {
		return
	}

	// 组织跟该任务相关的设备ID
	if len(taskEntity.DeviceIds) == 0 {
		return
	}

	for index := 0; index < len(taskEntity.DeviceIds); index++ {
		deviceId := Number.MakeInt64(taskEntity.DeviceIds[index])

		deviceEntity := commRedisService.GetEntityById(edgeEntity.Type.DeviceEntity.Type(), deviceId)
		if deviceEntity == nil {
			continue
		}

		// 均摊CPU的损耗
		e.sleep(currentTime, timeInv, int64(len(taskEntity.DeviceIds)), int64(index))

		// 执行任务
		e.executeTask(deviceEntity.(*edgeEntity.DeviceEntity), taskEntity)
	}

}

func (e *CollectorExchangeService) sleep(startTime int64, timeInterval int64, deviceCount int64, index int64) {
	configs, err := commConfig.GetConfigParam("serverConfig")
	if err != nil {
		return
	}

	average := Map.GetOrDefault(configs, "average", false)
	if true != average {
		return
	}

	// 检查：是否需要休眠
	step := time.Now().UnixMilli() - startTime
	unit := timeInterval / deviceCount
	if step < index*unit {
		time.Sleep(time.Duration(unit) * time.Millisecond)
	}
}

func (e *CollectorExchangeService) getTimeInterval(taskEntity *edgeEntity.OperateMonitorTaskEntity) (t int64, err error) {
	// 定义一个最终的异常拦截，用来防止可能的代码BUG
	defer func() {
		if r := recover(); r != nil {
			t = -1
			err = errors.New("参数不合法")
		}
	}()

	timeMode := taskEntity.TaskParam["timeMode"].(string)
	timeUnit := taskEntity.TaskParam["timeUnit"].(string)
	timeInv := Number.MakeInt64(taskEntity.TaskParam["timeInterval"])

	if Method.HasEmpty(timeMode, timeUnit) {
		return int64(-1), errors.New("参数不合法")
	}

	if timeMode == "interval" {
		if timeUnit == "second" {
			return timeInv * 1000, nil
		}
		if timeUnit == "minute" {
			return timeInv * 1000 * 60, nil
		}
		if timeUnit == "hour" {
			return timeInv * 1000 * 3600, nil
		}
		if timeUnit == "day" {
			return timeInv * 1000 * 3600 * 24, nil
		}
	}

	return int64(-1), errors.New("参数不合法")
}

func (e *CollectorExchangeService) executeTask(deviceEntity *edgeEntity.DeviceEntity, taskEntity *edgeEntity.OperateMonitorTaskEntity) {
	// 通过时间戳，判断设备服务是否正在运行
	if !commRedisStatus.IsActive("device", "device", 60*1000) {
		return
	}

	taskRequestVO := e.buildPackageRequestVO(deviceEntity, taskEntity)
	if len(taskRequestVO.RequestVOS) == 0 {
		return
	}

	// 总的超时
	if taskRequestVO.Timeout > 60*1000 {
		taskRequestVO.Timeout = 60 * 1000
	}

	//填写UID，从众多方便返回的数据中，识别出来对应的返回报文
	if taskRequestVO.Uuid == "" {
		taskRequestVO.Uuid = Uuid.RandomUUID()
	}

	// 发出操作请求
	err := commRedisRpc.Device.Client.Request.Push(taskRequestVO)
	if err != nil {
		return
	}

	// 等待消息的到达：根据动态key
	taskRespondVO, _ := commRedisRpc.Device.Client.Respond.Pop(taskRequestVO.Uuid, time.Duration(taskRequestVO.Timeout+1000)*time.Millisecond)
	if !e.isValid(taskRespondVO) {
		return
	}

	// 检查：下游的持久化队列，是否已经进入50%的繁忙状态
	busy, err := commRedisRpc.Persist.Client.ValueRequest.IsBusy(50)
	if err != nil {
		return
	}
	if busy {
		time.Sleep(100 * time.Millisecond)
	}

	err = commRedisRpc.Persist.Client.ValueRequest.Push(taskRespondVO)
	if err != nil {
		return
	}
}

func (e *CollectorExchangeService) isValid(taskRespondVO *commRedisRpc.TaskRespondVO) bool {
	if taskRespondVO == nil || len(taskRespondVO.RespondVOS) == 0 {
		return false
	}

	for _, operateRespondVO := range taskRespondVO.RespondVOS {
		if operateRespondVO.Data == nil {
			continue
		}

		return true
	}

	return false
}

func (e *CollectorExchangeService) buildPackageRequestVO(deviceEntity *edgeEntity.DeviceEntity, operateTemplateEntity *edgeEntity.OperateMonitorTaskEntity) *commRedisRpc.TaskRequestVO {
	taskRequestVO := commRedisRpc.TaskRequestVO{}
	taskRequestVO.ClientName = "system_controller"
	taskRequestVO.Uuid = Uuid.RandomUUID()
	taskRequestVO.RequestVOS = make([]*commRedisRpc.OperateRequestVO, 0)

	totalTimeout := 0
	for _, param := range operateTemplateEntity.TemplateParam {
		operateRequestVO := commRedisRpc.Type.OperateRequestVO.New()
		operateRequestVO.BindRequestMap(param)
		operateRequestVO.DeviceType = deviceEntity.DeviceType
		operateRequestVO.Manufacturer = deviceEntity.Manufacturer
		operateRequestVO.DeviceName = deviceEntity.DeviceName
		operateRequestVO.Uuid = Uuid.RandomUUID()

		if operateRequestVO.Param == nil {
			operateRequestVO.Param = make(map[string]interface{})
		}
		Map.Append(operateRequestVO.Param, deviceEntity.DeviceParam)

		taskRequestVO.RequestVOS = append(taskRequestVO.RequestVOS, operateRequestVO)

		totalTimeout += operateRequestVO.Timeout
	}

	taskRequestVO.Timeout = totalTimeout
	return &taskRequestVO
}
